<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>项目文档说明</title>
    <!-- 引入Tailwind CSS -->
    <script src="/js/tailwindcss.js"></script>
    <!-- 引入Font Awesome图标 -->
    <link href="/css/font-awesome.min-all.css" rel="stylesheet">

    <!-- 配置Tailwind自定义颜色 -->
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#10B981',
                        neutral: '#64748B',
                        light: '#F8FAFC',
                        dark: '#1E293B'
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>

    <!-- 自定义工具类 - 修复折叠样式冲突 -->
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }

            /* 段落折叠样式 */
            .section-content {
                max-height: 0;
                overflow: hidden;
                transition: max-height 0.3s ease-out;
            }
            .section-active {
                max-height: 2000px;
                transition: max-height 0.6s ease-in;
            }

            /* 流程图折叠样式 */
            .flowchart-content {
                max-height: 0;
                overflow: hidden;
                transition: max-height 0.3s ease-out;
            }
            .flowchart-active {
                max-height: 1500px;
                transition: max-height 0.6s ease-in;
            }
        }
    </style>
</head>
<body class="bg-gray-50 text-gray-800 font-sans">
<!-- 页面容器 -->
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-10">
    <!-- 项目标题区域 -->
    <header class="mb-12 text-center">
        <h1 class="text-4xl font-bold text-dark mb-4">应用监控事件信息上送系统</h1>
        <p class="text-neutral text-lg"></p>

        <!-- 跳转到Swagger接口文档的按钮 -->
        <a href="/swagger-ui/index.html" target="_blank"
           class="inline-flex items-center mt-6 px-6 py-3 bg-primary hover:bg-primary/90 text-white font-medium rounded-lg transition-all shadow-md hover:shadow-lg">
            <i class="fa fa-book mr-2"></i>
            查看用于测试的接口文档
        </a>
    </header>

    <!-- 主要内容区域 -->
    <main class="space-y-10">
        <!-- 项目概述 -->
        <section class="bg-white rounded-xl shadow-sm p-6">
            <div class="collapsible-header flex items-center justify-between cursor-pointer" data-target="overview">
                <h2 class="text-2xl font-semibold text-dark">项目概述</h2>
                <span class="flex items-center text-neutral">
                        <i class="fa fa-minus mr-1"></i>
                        <span class="text-sm">收起</span>
                    </span>
            </div>
            <div id="overview" class="section-content section-active mt-4 text-gray-700">
                <p class="mb-4">
                    为减少业务系统本身的运行维护成本，独立开发了应用监控事件信息上送系统(即本系统)，本系统独立部署。
                </p>
                <p>
                    借助Redis, 业务系统将关键事件信息存储在Redis中，本系统通过定时拉取redis信息, 经计算压缩等操作后存储到oracle数据库,
                    并定时通过UDP协议将事件信息上报至总行监控接口。
                </p>
            </div>
        </section>

        <!-- 背景介绍 -->
        <section class="bg-white rounded-xl shadow-sm p-6">
            <div class="collapsible-header flex items-center justify-between cursor-pointer" data-target="background">
                <h2 class="text-2xl font-semibold text-dark">背景介绍</h2>
                <span class="flex items-center text-neutral">
                        <i class="fa fa-minus mr-1"></i>
                        <span class="text-sm">收起</span>
                    </span>
            </div>
            <div id="background" class="section-content section-active mt-4 text-gray-700">
                <p class="mb-4">
                    对业务系统的关键业务流程、应用组件及外部系统连通性进行实时监控，通过UDP协议将预警信息按指定格式上报至总行监控接口
                </p>
            </div>
        </section>

        <!-- 系统架构 -->
        <section class="bg-white rounded-xl shadow-sm p-6">
            <div class="collapsible-header flex items-center justify-between cursor-pointer" data-target="architecture">
                <h2 class="text-2xl font-semibold text-dark">系统架构</h2>
                <span class="flex items-center text-neutral">
                        <i class="fa fa-minus mr-1"></i>
                        <span class="text-sm">收起</span>
                    </span>
            </div>
            <div id="architecture" class="section-content section-active mt-4 text-gray-700">
                <p class="mb-4">项目采用的技术架构和整体设计：</p>

                <!-- 可折叠的架构流程图 -->
                <div class="mt-6 border border-gray-200 rounded-lg overflow-hidden">
                    <div class="flowchart-header flex items-center justify-between cursor-pointer" data-target="architecture-chart">
                        <h3 class="font-medium text-gray-700">整体业务流程</h3>
                        <span class="flex items-center text-neutral">
                                <i class="fa fa-minus mr-1"></i>
                                <span class="text-sm">收起</span>
                            </span>
                    </div>
                    <div id="architecture-chart" class="flowchart-content flowchart-active">
                        <div class="p-4 flex justify-center bg-gray-50">
                            <!-- 实际架构图 -->
                            <img src="/img/overall-process.jpg" alt="整体业务流程" class="rounded shadow-md"/>
                        </div>

                    </div>
                </div>

                <div class="mt-4">
                    <h3 class="text-xl font-medium mt-6 mb-2">核心技术栈</h3>
                    <ul class="list-disc pl-6 space-y-1">
                        <li>后端框架：Spring Boot 2.7.x</li>
                        <li>数据库：ORACLE</li>
                        <li>ORM框架：springboot data JPA</li>
                        <li>API文档：Swagger/OpenAPI</li>
                        <li>其他：Redis, UDP, Scheduled, XML, MAVEN</li>
                    </ul>
                </div>
            </div>
        </section>

        <!-- 使用方式 -->
        <section class="bg-white rounded-xl shadow-sm p-6">
            <div class="collapsible-header flex items-center justify-between cursor-pointer" data-target="usage">
                <h2 class="text-2xl font-semibold text-dark">使用方式</h2>
                <span class="flex items-center text-neutral">
                        <i class="fa fa-minus mr-1"></i>
                        <span class="text-sm">收起</span>
                    </span>
            </div>
            <div id="usage" class="section-content section-active mt-4 text-gray-700">
                <p class="mb-4 text-lg">业务系统使用步骤：</p>

                <ol class="list-decimal pl-6 space-y-4">
                    <li class="pb-2 border-b border-gray-100">
                        <strong>引入依赖</strong>
                        <pre class="bg-gray-100 p-3 rounded-md mt-1 overflow-x-auto">
    <code>&lt;dependency&gt;
        &lt;groupId&gt;com.kjlink.widget&lt;/groupId&gt;
        &lt;artifactId&gt;monitoring-common&lt;/artifactId&gt;
        &lt;version&gt;1.0.0-SNAPSHOT&lt;/version&gt;
    &lt;/dependency&gt;</code></pre>
                    </li>

                    <li class="pb-2 border-b border-gray-100">
                        <strong> 配置 发送bean</strong>
                        <p class="mt-1">保证redis一致; 配置TTL 单位秒</p>
                        <pre class="bg-gray-100 p-3 rounded-md mt-1 overflow-x-auto"><code> @Bean
public MonitorEventSender monitorEventSender() {
 MonitorEventSender monitoringSendBean = new MonitorEventSender(stringRedisTemplate);
 monitoringSendBean.setTtl(60 * 60);
 return monitoringSendBean;
}</code></pre>
                    </li>

                    <li class="pb-2 border-b border-gray-100">
                        <strong>使用MonitorEventSender发送事件</strong>
                        <p class="mt-1">注意组装完整的MonitorDataModel</p>
                        <pre class="bg-gray-100 p-3 rounded-md mt-1 overflow-x-auto"><code>MonitorEventSender#sendEvent(MonitorDataModel)</code>
                        </pre>
                    </li>
                </ol>

                <p class="mb-4 text-lg">monitoring-server 服务端(本系统)：</p>
                <ol class="list-decimal pl-6 space-y-4">
                    <li class="pb-2 border-b border-gray-100">
                        <strong>参见配置文件`application.properties`</strong>
                        <p class="mt-1">- 除oracle和redis外, 主要是定时任务的一些参数和upd服务地址</p>
                        <pre class="bg-gray-100 p-3 rounded-md mt-1 overflow-x-auto"><code>#*******************************************************************************
# event  task config  @see MonitorConfigParams
# *******************************************************************************
# will register task
monitor.task.enabled=false
# event expire minutes
monitor.event.expire-minutes=60
# batch window minutes
monitor.batch.window.minutes=2
# task consumer interval minutes
monitor.task.consumer.interval=1
# task expired minutes
monitor.task.expired.interval=60
# task send interval minutes
monitor.task.send.interval=2

# *******************************************************************************
# udp config
# *******************************************************************************
# enable local udp server for test
monitor.udp.test.server=true
monitor.udp.server.ip=127.0.0.1
monitor.udp.server.port=9876
</code></pre>
                    </li>
                </ol>
            </div>


        </section>

        <!-- 核心流程 -->
        <section class="bg-white rounded-xl shadow-sm p-6">
            <div class="collapsible-header flex items-center justify-between cursor-pointer" data-target="processes">
                <h2 class="text-2xl font-semibold text-dark">核心流程</h2>
                <span class="flex items-center text-neutral">
                        <i class="fa fa-minus mr-1"></i>
                        <span class="text-sm">收起</span>
                    </span>
            </div>
            <div id="processes" class="section-content section-active mt-4 text-gray-700">
                <p class="mb-4">项目的核心业务流程说明：</p>

                <!-- 可折叠的流程图1 -->
                <div class="mt-6 border border-gray-200 rounded-lg overflow-hidden">
                    <div class="flowchart-header flex items-center justify-between cursor-pointer" data-target="registration-flow">
                        <h3 class="font-medium text-gray-700">事件收集-生成批次-事件压缩-udp上报</h3>
                        <span class="flex items-center text-neutral">
                                <i class="fa fa-minus mr-1"></i>
                                <span class="text-sm">收起</span>
                            </span>
                    </div>
                    <div id="registration-flow" class="flowchart-content flowchart-active">
                        <div class="p-4 flex justify-center bg-gray-50">
                            <img src="/img/sequence.png" alt="sequence" class="rounded shadow-md"/>
                        </div>
                        <div class="p-4 bg-white">
                            <p>说明：</p>
                            <ol class="list-decimal pl-6 mt-1 space-y-1">
                                <li>业务系统写入事件到redis</li>
                                <li>本系统定时拉取redis中的事件列表(定时任务) </li>
                                <li>
                                    <ul>
                                        <li>存储原始事件</li>
                                        <li>判断当前压缩传窗口内是否存在批次</li>
                                        <li>存在未上报批次, 则合并事件到该批次</li>
                                        <li>不存在上报批次,但是存在上一个窗口内上报失败的批次(是否可以只查询上一个压缩窗口)，则提取失败批次的相关信息,带入当前新创建的批次</li>
                                        <li>均不存在，创建批次</li>
                                    </ul>
                                </li>
                                <li>删除redis中已处理的事件</li>
                            </ol>
                        </div>
                    </div>
                </div>

                <!-- 可折叠的流程图2 -->
                <div class="mt-6 border border-gray-200 rounded-lg overflow-hidden">
                    <div class="flowchart-header flex items-center justify-between cursor-pointer" data-target="data-flow">
                        <h3 class="font-medium text-gray-700">其他定时任务</h3>
                        <span class="flex items-center text-neutral">
                                <i class="fa fa-minus mr-1"></i>
                                <span class="text-sm">收起</span>
                            </span>
                    </div>
                    <div id="data-flow" class="flowchart-content flowchart-active">
                        <div class="p-4 flex justify-center bg-gray-50">
                            <!--<img src="https://picsum.photos/800/300?random=3" alt="数据处理流程图" class="rounded shadow-md"/>-->
                        </div>
                        <div class="p-4 bg-white ">
                            <p class="font-bold">1. UDP定时上报事件数据</p>
                            <ol class="list-decimal pl-6 mt-1 space-y-1">
                                <li>定时查询所有时间窗口已经结束的未上传的批次</li>
                                <li>逐条处理,组装xml格式的UDP报文, 发送UDP报文</li>
                                <li>根据上传结果更新批次状态</li>
                            </ol>
                            <p class="font-bold mt-2">2. UDP定时上报事件数据</p>
                            <ol class="list-decimal pl-6 mt-1 space-y-1">
                                <li>定时查询所有时间窗口已经结束的未上传的批次</li>
                                <li>逐条处理,组装xml格式的UDP报文, 发送UDP报文</li>
                                <li>更加上传结果更新批次状态</li>
                            </ol>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- 常见问题 -->
        <section class="bg-white rounded-xl shadow-sm p-6">
            <div class="collapsible-header flex items-center justify-between cursor-pointer" data-target="faq">
                <h2 class="text-2xl font-semibold text-dark">常见问题</h2>
                <span class="flex items-center text-neutral">
                        <i class="fa fa-minus mr-1"></i>
                        <span class="text-sm">收起</span>
                    </span>
            </div>
            <div id="faq" class="section-content section-active mt-4 text-gray-700">
                <div class="space-y-4">
                    <div class="border-l-4 border-primary pl-4 py-1">
                        <h3 class="font-medium">Q: 项目启动时报数据库连接错误怎么办？</h3>
                        <p class="mt-1">A:
                            请检查数据库是否正常运行，配置文件中的数据库连接信息是否正确，以及数据库用户是否有足够的权限。</p>
                    </div>

                    <div class="border-l-4 border-primary pl-4 py-1">
                        <h3 class="font-medium">Q: 如何测试？</h3>
                        <p class="mt-1">A:
                            先关闭定定时任务,手动通过swagger页面人工触发测试,先保证业务连通性。</p>
                    </div>

                    <div class="border-l-4 border-primary pl-4 py-1">
                        <h3 class="font-medium">Q: 其他？</h3>
                        <p class="mt-1">A: 参见配置文件
                        </p>
                    </div>
                </div>
            </div>
        </section>
    </main>

    <!-- 页脚信息 -->
    <footer class="mt-16 pt-8 border-t border-gray-200 text-center text-neutral">
        <div class="mb-4">
            <p><strong>作者：</strong>Vic.xu</p>
            <p><strong>最后更新时间：</strong>2027年8月 </p>
        </div>
        <p class="text-sm">© 2025 kjlink 版权所有</p>
    </footer>
</div>

<!-- JavaScript代码 - 修复折叠逻辑 -->
<script>
    document.addEventListener('DOMContentLoaded', function () {
        // 段落折叠/展开功能
        document.querySelectorAll('.collapsible-header').forEach(header => {
            header.addEventListener('click', function () {
                // 通过data-target属性获取对应内容区域
                const targetId = this.getAttribute('data-target');
                const content = document.getElementById(targetId);
                const icon = this.querySelector('i');
                const text = this.querySelector('span span');

                // 切换段落展开状态
                content.classList.toggle('section-active');

                // 更新图标和文字提示
                if (content.classList.contains('section-active')) {
                    icon.classList.remove('fa-plus');
                    icon.classList.add('fa-minus');
                    text.textContent = '收起';
                } else {
                    icon.classList.remove('fa-minus');
                    icon.classList.add('fa-plus');
                    text.textContent = '展开';
                }
            });
        });

        // 流程图折叠/展开功能
        document.querySelectorAll('.flowchart-header').forEach(header => {
            header.addEventListener('click', function () {
                // 通过data-target属性获取对应内容区域
                const targetId = this.getAttribute('data-target');
                const content = document.getElementById(targetId);
                const icon = this.querySelector('i');
                const text = this.querySelector('span span');

                // 切换流程图展开状态
                content.classList.toggle('flowchart-active');

                // 更新图标和文字提示
                if (content.classList.contains('flowchart-active')) {
                    icon.classList.remove('fa-plus');
                    icon.classList.add('fa-minus');
                    text.textContent = '收起';
                } else {
                    icon.classList.remove('fa-minus');
                    icon.classList.add('fa-plus');
                    text.textContent = '展开';
                }
            });
        });
    });
</script>
</body>
</html>